/******************************************************************************
 * Copyright (C), 2014, BeeIoT Tech. Co., Ltd. 
 * FileName:        gprs.c
 * Author:          lvxin 
 * Version :        1.0
 * Date:            2014-12-02 11:31:11
 * Description:
 * Function List:   1. -------
 * History:
 * <author>     <time>                <version >  <desc> 
 * lvxin        2014-12-02 11:31:11   1.0         build this moudle 
 *****************************************************************************/

/******************************************************************************
 *  *INCLUDES
 *  */
#include "option.h"
#include "smset.h"
#include "object.h"
#include "SIM900A.h"
#include "gprs.h"
#include "string.h"
/*#include "dev_platform.h"*/

/******************************************************************************
 *  *MICROS
 *  */
#define     DIM(x)  (sizeof(x)/sizeof(x[0]))

/******************************************************************************
 *  *CONSTANTS
 *  */

/******************************************************************************
 *  *TYPEDEFS
 *  */

typedef struct _gprs_stat
{
    int usability;  //gprs是否可用 0-不可用 1-可用
    int initted;    //gprs是否已初始化 0-未初始化 1--初始化
    int TCP_BUSY;   //gprs是否传输完成 0 完成 1 未完成
    int TCP_RET;    //gprs处理完成后返回值
    char *read_buf; //gprs网络数据读取缓冲区
    uint8_t is_reading; //gprs是否读在读取网络数据 0 --未读取  1--有读取
    uint8_t is_readover;//gprs是否读完网络数据  0 --未完成 1 --完成
    uint8_t once_initted; //仅需要初始化一次的参数是否已初始化 0 --未初始化 1--已初始化
    int read_size;  //gprs读取字节数
}gprs_stat_t;


enum _cip_stat{
    IP_INITIAL  =   0,
    IP_START    =   1,
    IP_CONFIG   =   2,
    IP_GPRSACT  =   3,
    IP_STATUS   =   4,
    TCP_CONNECTING    = 6,
    UDP_CONNECTING    = 7,
    SERVER_LINSTENING = 8,
    CONNECT_OK  =   9,
    TCP_CLOSING =   10,
    UDP_CLOSING =   11,
    TCP_CLOSED  =   12,
    UDP_CLOSED  =   13,
    PDP_DEACT   =   14
}; 

//cip状态结构体
typedef struct _cip_statu
{
    char string[20]; //保存字符串
    char flag;      //更新标识 0 --已读取 1 --状态有更新
}cip_statu_t;

//保存cip状态值
typedef struct _stat_value
{
    char *stat_string;
    enum _cip_stat value;
}stat_value_t;


/******************************************************************************
 *  *LOCAL VARIABLES
 *  */
static gprs_stat_t l_gprs_stat; //gprs使用的全局状态

static cip_statu_t l_cip_statu={
    {0},
    0,
}; //获取cip状态时使用

const static stat_value_t l_stat_value[]={
    {"IP INITIAL"         , IP_INITIAL          },
    {"IP START"           , IP_START            },
    {"IP CONFIG"          , IP_CONFIG           },
    {"IP GPRSACT"         , IP_GPRSACT          },
    {"IP STATUS"          , IP_STATUS           },
    {"TCP CONNECTING"     , TCP_CONNECTING      },
    {"UDP CONNECTING"     , UDP_CONNECTING      },
    {"SERVER LINSTENING"  , SERVER_LINSTENING   },
    {"CONNECT OK"         , CONNECT_OK          },
    {"TCP CLOSING"        , TCP_CLOSING         },
    {"UDP CLOSING"        , UDP_CLOSING         },
    {"TCP CLOSED"         , TCP_CLOSED          },
    {"UDP CLOSED"         , UDP_CLOSED          },
    {"PDP DEACT"          , PDP_DEACT           },
};                    

/******************************************************************************
 * Function:        SIM900A_gprs_init
 * Description:     初始化GPRS
 * Calls:           
 * Called By:       
 * Input:           flag  0 --不使用GPRS 1 --初始化gprs 
 * Return:          GPRS是否可用 0 --可用  -1 --不可用
 * Others:          none
 *****************************************************************************/
int gprs_init(uint8_t flag)
{ 
    if (flag == 1)
    {
        do
        {
            l_gprs_stat.initted = 0;
            l_gprs_stat.usability = 1;
            l_gprs_stat.read_buf = NULL;
            l_gprs_stat.is_reading = 0;

            SIM900A_run ("AT+CIPSHUT\r\n", 3000, NULL, NULL);  //关闭场景
            SIM900A_run ("AT+CIPMUX=0\r\n", 3000, NULL, NULL); //单路IP连接
            SIM900A_run ("AT+CIPHEAD=1\r\n", 3000, NULL, NULL);//接收数据时显示IP头

            if (l_gprs_stat.once_initted != 1)
            {
                if (SIM900A_run ("AT+CGCLASS=\"B\"\r\n", 5000, NULL, NULL) != AT_RETURN_OK) break;
                if (SIM900A_run ("AT+CGDCONT=1,\"IP\",\"CMNET\"\r\n", 5000, NULL, NULL) != AT_RETURN_OK) break; 
                l_gprs_stat.once_initted = 1;
            }

            if (SIM900A_run ("AT+CGATT=1\r\n", 5000, NULL, NULL) != AT_RETURN_OK)  //附着GPRS业务
            {
                l_gprs_stat.usability = 0;
                break;
            }
            SIM900A_run ("AT+CIPCSGP=1,\"CMNET\"\r\n", 5000, NULL, NULL);
            l_gprs_stat.initted = 1;
            return 0;
        }while(0);
    }
    return -1;
}

//tcp是否空闲
int is_TCP_NO_BUSY(int argc, void *argv[])
{
    return l_gprs_stat.TCP_BUSY == 0;
}

//tcp连接是否已建立
int is_TCP_CONNECTED(int argc, void *argv[])
{
    return l_gprs_stat.TCP_BUSY == 2;
}

//tcp连接是否失败
int is_TCP_CONNECT_FAIL(int argc, void *argv[])
{
    return l_gprs_stat.TCP_BUSY == -1;
}
//tcp是否还未关闭
int is_TCP_NO_CLOSED(int argc, void *argv[])
{
    return l_gprs_stat.TCP_BUSY != 0;
}

//tcp是否sendok
int is_TCP_SENDOK(int argc, void *argv[])
{
    /*return l_gprs_stat.TCP_RET != 0;*/
    return l_gprs_stat.TCP_RET == -1;
}

//cipstatus是否更新
int is_CIPSTATUS_UPDATED(int argc, void *argv[])
{
    return l_cip_statu.flag == 0;
}

//tcp是否read
int is_READING(int argc, void *argv[])
{
    /*return l_gprs_stat.TCP_RET != 0;*/
    return l_gprs_stat.is_readover == 0;
}

void gprs_tcp_set_SENDOK(void)
{
    l_gprs_stat.TCP_RET = 0;
}

void gprs_tcp_set_SENDFAIL(void) //sendfail 发送失败
{
    l_gprs_stat.TCP_RET = -2;
}
void gprs_tcp_set_SENDSTART(void)
{
    l_gprs_stat.TCP_RET = -1;
}

void gprs_tcp_set_CONNOK(void)
{
    l_gprs_stat.TCP_BUSY = 2;//连接已建立
}

void gprs_tcp_set_CLOSED(void)
{
    l_gprs_stat.TCP_BUSY = 0;  //连接已关闭
    l_gprs_stat.is_readover = 1;

    if (l_gprs_stat.read_buf != NULL)
    {
        if (strlen(l_gprs_stat.read_buf) == 0)
        {
            l_gprs_stat.read_size = 0; //网络读取字节数归零
            l_gprs_stat.read_buf[0] = 0;
        }
        l_gprs_stat.read_buf = NULL;
    }
}

void gprs_tcp_set_FAIL(void)
{
    l_gprs_stat.TCP_RET = -1;
    l_gprs_stat.TCP_BUSY = -1;  //连接失败
}

//获得网络状态
int gprs_net_get_stat(void)
{
    int i;
    int total = DIM(l_stat_value);
    l_cip_statu.flag = 0;
    if(SIM900A_run ("AT+CIPSTATUS\r\n", 3000, NULL, NULL) == AT_RETURN_OK)
    {
        if(wait_timeout(is_CIPSTATUS_UPDATED, 3000, 0, NULL) == -1)
        {
            return AT_RETURN_TIME_OUT;
        }

        /*DBG_PRINTF("当前网络状态：%s\n", l_cip_statu.string);*/
        for (i = 0; i < total; i ++)
        {
            if (strncmp(l_stat_value[i].stat_string,
                        l_cip_statu.string,
                        strlen(l_stat_value[i].stat_string)) == 0)
                        /*strlen(l_stat_value[i].stat_string)) == 0)*/
            {
                DBG_PRINTF("当前网络状态：%s\t[value]%d\n", 
                        l_stat_value[i].stat_string, 
                        l_stat_value[i].value
                        );
                return l_stat_value[i].value;
            }
        }
    }
    return AT_RETURN_ERROR;
}

//建立tcp连接
/******************************************************************************
 * Function:        gprs_net_connect
 * Description:     建立网络连接
 * Calls:            
 * Called By:        
 * Input:           type --连接类型  addr --连接地址 port --端口号
 * Return:          0 --连接成功  -1 --连接失败
 * Others:           
 *****************************************************************************/
int gprs_net_connect(char *type, char *addr, int port)
{
    /*static retry_times = 0; //重试连接次数*/
    int ret = -1;
        //读取当前cip状态
        int stat = -1;

    mdelay(500);
    l_gprs_stat.TCP_RET = -1;
    l_gprs_stat.TCP_BUSY = 0;

    /*SIM900A_run ("AT+CGATT=1\r\n", 5000, NULL, NULL);//附着gprs*/
    if (l_gprs_stat.initted == 1 || gprs_init(1) == 0)//是否需要初始化
    {
        SIM900A_run ("ATH\r\n", 3000, NULL, NULL);
        stat = gprs_net_get_stat();
        
        if (stat == AT_RETURN_ERROR) return -1;

        DBG_PRINTF ("[IP_INITIAL]: %d\t[TCP_CLOSED]: %d\n", IP_INITIAL, TCP_CLOSED);
        DBG_PRINTF ("[STATE]: %d\n", stat);

        /*判断当前连接状态*/
        switch (stat)
        {
            case IP_INITIAL :
            case TCP_CLOSED :
                break;
            case PDP_DEACT:
                SIM900A_run ("AT+CIPSHUT\r\n", 3000, NULL, NULL);
            default :
                if(SIM900A_run ("AT+CIPCLOSE=1\r\n", 3000, NULL, NULL) != AT_RETURN_CLOSEOK)
                {
                    gprs_init(1); //重新初始化gprs
                }
                break;
        }

        ret = SIM900A_perform_formatted (10000, NULL, NULL, "AT+CIPSTART=\"%s\",\"%s\",%d\r\n", type, addr, port);
    }
    /*
     * 执行完AT+CIPSTART后，如果连接成功则收到CONNECT OK
     * 不成功则收到 CONNECT FAIL
     */

    if (ret == AT_RETURN_OK)
    {
        //超时后关闭移动场景,并且重新初始化
        if(wait_timeout(is_TCP_NO_BUSY, 15000, 0, NULL) == -1)
        {
            gprs_net_shut();
            l_gprs_stat.initted = 0;
            return -1;
        };
        if (is_TCP_CONNECTED(0, NULL)) //TCP连接成功
        {
            return 0;
        }
        else if(is_TCP_CONNECT_FAIL(0, NULL)) //连接失败
        {
            return -1;
        }
    }
    return -1;
}

/******************************************************************************
 * Function:        gprs_net_shut()
 * Description:     断开CIP连接
 * Calls:            
 * Called By:        
 * Input:            
 * Return:           
 * Others:              
 *****************************************************************************/
void gprs_net_shut(void)
{
    SIM900A_run ("AT+CIPSHUT\r\n", 3000, NULL, NULL);
}

//格式化发送数据

/******************************************************************************
 * Function:        gprs_net_send_formatted
 * Description:     格式化发送数据到网络服务器
 * Calls:            
 * Called By:        
 * Input:            
 * Return:          0 --发送成功  -1 --发送失败
 * Others:          
 *****************************************************************************/
int gprs_net_send_formatted(const char *__restrict __fmt, ...)
{
    va_list va;
    int ret = -1;
    va_start(va, __fmt);

    ret = SIM900A_perform_formatted (5000, NULL, NULL, "AT+CIPSEND\r\n");
    if (ret == AT_RETURN_CON) //必须返回的字符为>时才可以发送数据
    {
        l_gprs_stat.TCP_RET = -1;
        mdelay (500);
        SIM900A_core_uvprintf((char *)__fmt, va);
        SIM900A_core_uprintf ("%c", 0x1a);
    }
    else
    {
        SIM900A_core_uprintf ("%c", 0x1b);
        va_end(va);
        return -1;
    }
    //等待sendok
    if(wait_timeout(is_TCP_SENDOK, 30000, 0, NULL) == -1)
    {
        SIM900A_core_uprintf ("%c", 0x1b);
        ret = -1;
    }
    else
    {
        ret = 0;
    }

    if (l_gprs_stat.TCP_RET == -2) ret = -1;
    va_end(va);
    return ret;
}

//读取网络数据
/******************************************************************************
 * Function:        gprs_net_read
 * Description:     读取网络数据
 * Calls:           
 * Called By:        
 * Input:           buffer  --数据缓冲区  
 *                  size    --读取的数据长度
 *                  timeout --毫秒级接收超时
 * Return:          -1 --读取超时
 *                  0 --连接断开
 *                  n --读取的字符数，此时buffer[0]会被写入0
 * Others:          
 *****************************************************************************/
int gprs_net_read(int timeout, char *buffer, int size)
{
    if (l_gprs_stat.TCP_BUSY == 0)
    {
        DBG_PRINTF ("[gprs_net_read连接关闭]\n");
        return 0;
    }

    l_gprs_stat.read_buf = buffer;
    l_gprs_stat.read_size = size;
    l_gprs_stat.is_reading = 1; //开始读取
    l_gprs_stat.is_readover = 0;//开始读取

    if(wait_timeout(is_READING, timeout, 0, NULL) == -1)
    {
        DBG_PRINTF ("[gprs_net_read超时]\n");
        return -1;
    }

    l_gprs_stat.read_buf = NULL;
    return l_gprs_stat.read_size;
}

//设置cipstatu属性，由接收到STATE:字段的处理函数调用
void gprs_set_cip_statu(char *str)
{
    memset (l_cip_statu.string, 0, 20);                 
    strncpy (l_cip_statu.string, str, 20);
    l_cip_statu.flag = 1; //状态有更新
}

/******************************************************************************
 * Function:        wait_timeout
 * Description:     根据条件，等待延时，根据条件返回超时或所耗时间
 * Calls:           mdelay()
 * Called By:       
 * Input:           condition --条件处理函数
 *                  argc        --传递给condition函数的参数个数
 *                  argv        --传递给condition函数的参数列表 
 * Return:          -1 --超时  N --耗时
 * Others:          none
 *****************************************************************************/
int wait_timeout(int (condition)(int,void**), int ms_timeout, int argc, void **argv)
{
    int count = 0;
    while (condition(argc, argv)){
        if (++ count > ms_timeout)
        {
            /*DBG_PRINTF ("error\n");*/
            /*l_sim_stat.TCP_BUSY = 0;*/
            return -1;
        }
        mdelay (1);
#if (PLATFORM == LPC1114)
        FEED_DOG();
#endif
    };
    return count;
}

//处理"+IPD"
int at_recv_IPD_cb(char *buffer)
{
    char *data = strstr(buffer,":") + 1;
    if (l_gprs_stat.is_reading == 1 
            && l_gprs_stat.read_buf != NULL)
    {
        if (l_gprs_stat.read_size == 0) //读取完毕,或网络关闭
        {
            l_gprs_stat.read_buf[0] = 0;
            l_gprs_stat.is_readover = 1;
            l_gprs_stat.is_reading = 0; //结束读取
            return 0;
        }
        strncpy (l_gprs_stat.read_buf, data, l_gprs_stat.read_size-1);
        l_gprs_stat.read_size = strlen (l_gprs_stat.read_buf) + 1;
        l_gprs_stat.is_readover = 1;
        l_gprs_stat.is_reading = 0; //结束读取
        l_gprs_stat.read_buf = NULL;
    }
    return 0;
}

